home *** CD-ROM | disk | FTP | other *** search
/ OpenGL Superbible (2nd Edition) / OpenGL SuperBible e2.iso / tools / GLUT-3.7 / PROGS / ADVANCED / shadowvol.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-08-12  |  8.5 KB  |  374 lines

  1.  
  2. /* shadowvol.c - by Tom McReynolds, SGI */
  3.  
  4. /* Shadows: Shadow maps */
  5.  
  6. #include <GL/glut.h>
  7. #include <stdlib.h>
  8.  
  9. /* Demonstrate shadow volumes */
  10.  
  11. /* Create a single component texture map */
  12. GLfloat *
  13. make_texture(int maxs, int maxt)
  14. {
  15.   int s, t;
  16.   static GLfloat *texture;
  17.  
  18.   texture = (GLfloat *) malloc(maxs * maxt * sizeof(GLfloat));
  19.   for (t = 0; t < maxt; t++) {
  20.     for (s = 0; s < maxs; s++) {
  21.       texture[s + maxs * t] = ((s >> 4) & 0x1) ^ ((t >> 4) & 0x1);
  22.     }
  23.   }
  24.   return texture;
  25. }
  26.  
  27. enum {
  28.   SPHERE = 1, CONE, LIGHT, SHADOWVOL
  29. };
  30.  
  31. typedef struct {
  32.   GLfloat *verticies;
  33.   GLfloat *normal;
  34.   int n;                /* number of verticies */
  35. } ShadObj;
  36.  
  37. GLfloat shadVerts[] =
  38. {30.f, 30.f, -350.f,
  39.   60.f, 20.f, -340.f,
  40.   40.f, 40.f, -400.f};
  41.  
  42. GLfloat shadNormal[] =
  43. {1.f, 1.f, 1.f};
  44. ShadObj shadower;
  45.  
  46. enum {
  47.   X, Y, Z
  48. };
  49.  
  50. /* simple way to extend a point to build shadow volume */
  51. void
  52. extend(GLfloat new[3], GLfloat light[3], GLfloat vertex[3], GLfloat t)
  53. {
  54.   GLfloat delta[3];
  55.  
  56.   delta[X] = vertex[X] - light[X];
  57.   delta[Y] = vertex[Y] - light[Y];
  58.   delta[Z] = vertex[Z] - light[Z];
  59.  
  60.   new[X] = light[X] + delta[X] * t;
  61.   new[Y] = light[Y] + delta[Y] * t;
  62.   new[Z] = light[Z] + delta[Z] * t;
  63. }
  64.  
  65. /* Create a shadow volume in a display list */
  66. /* XXX light should have 4 compoents */
  67. void
  68. makeShadowVolume(ShadObj * shadower, GLfloat light[3],
  69.   GLfloat t, GLint dlist)
  70. {
  71.   int i;
  72.   GLfloat newv[3];
  73.  
  74.   glNewList(dlist, GL_COMPILE);
  75.   glDisable(GL_LIGHTING);
  76.   glBegin(GL_QUADS);
  77.   /* for debugging */
  78.   glColor3f(.2f, .8f, .4f);
  79.   for (i = 0; i < shadower->n; i++) {
  80.     glVertex3fv(&shadower->verticies[i * 3]);
  81.     extend(newv, light, &shadower->verticies[i * 3], t);
  82.     glVertex3fv(newv);
  83.     extend(newv, light, &shadower->verticies[((i + 1) % shadower->n) * 3],
  84.       t);
  85.     glVertex3fv(newv);
  86.     glVertex3fv(&shadower->verticies[((i + 1) % shadower->n) * 3]);
  87.   }
  88.   glEnd();
  89.   glEnable(GL_LIGHTING);
  90.   glEndList();
  91. }
  92.  
  93. void 
  94. sphere(void)
  95. {
  96.   glPushMatrix();
  97.   glTranslatef(60.f, -50.f, -360.f);
  98.   glCallList(SPHERE);
  99.   glPopMatrix();
  100. }
  101.  
  102. void 
  103. cone(void)
  104. {
  105.   glPushMatrix();
  106.   glTranslatef(-40.f, -40.f, -400.f);
  107.   glCallList(CONE);
  108.   glPopMatrix();
  109.  
  110. }
  111.  
  112. enum {
  113.   NONE, NOLIGHT, VOLUME, SHADOW
  114. };
  115.  
  116. int rendermode = NONE;
  117.  
  118. void
  119. menu(int mode)
  120. {
  121.   rendermode = mode;
  122.   glutPostRedisplay();
  123. }
  124.  
  125. GLfloat leftwallshadow[4][4];
  126. GLfloat floorshadow[4][4];
  127.  
  128. GLfloat lightpos[] =
  129. {50.f, 50.f, -340.f, 1.f};
  130.  
  131. /* render while jittering the shadows */
  132. void
  133. render(ShadObj * obj)
  134. {
  135.   static GLfloat shad_mat[] =
  136.   {1.f, .1f, .1f, 1.f};
  137.   GLfloat *v;           /* vertex pointer */
  138.   int i;
  139.  
  140.   /* material properties for objects in scene */
  141.   static GLfloat wall_mat[] =
  142.   {1.f, 1.f, 1.f, 1.f};
  143.  
  144.   /* Note: wall verticies are ordered so they are all front facing this lets
  145.      me do back face culling to speed things up.  */
  146.  
  147.   glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, wall_mat);
  148.  
  149.   /* floor */
  150.   /* make the floor textured */
  151.   glEnable(GL_TEXTURE_2D);
  152.  
  153.   /* Since we want to turn texturing on for floor only, we have to make floor 
  154.      a separate glBegin()/glEnd() sequence. You can't turn texturing on and
  155.      off between begin and end calls */
  156.   glBegin(GL_QUADS);
  157.   glNormal3f(0.f, 1.f, 0.f);
  158.   glTexCoord2i(0, 0);
  159.   glVertex3f(-100.f, -100.f, -320.f);
  160.   glTexCoord2i(1, 0);
  161.   glVertex3f(100.f, -100.f, -320.f);
  162.   glTexCoord2i(1, 1);
  163.   glVertex3f(100.f, -100.f, -520.f);
  164.   glTexCoord2i(0, 1);
  165.   glVertex3f(-100.f, -100.f, -520.f);
  166.   glEnd();
  167.  
  168.   glDisable(GL_TEXTURE_2D);
  169.  
  170.   /* walls */
  171.  
  172.   glBegin(GL_QUADS);
  173.   /* left wall */
  174.   glNormal3f(1.f, 0.f, 0.f);
  175.   glVertex3f(-100.f, -100.f, -320.f);
  176.   glVertex3f(-100.f, -100.f, -520.f);
  177.   glVertex3f(-100.f, 100.f, -520.f);
  178.   glVertex3f(-100.f, 100.f, -320.f);
  179.  
  180.   /* right wall */
  181.   glNormal3f(-1.f, 0.f, 0.f);
  182.   glVertex3f(100.f, -100.f, -320.f);
  183.   glVertex3f(100.f, 100.f, -320.f);
  184.   glVertex3f(100.f, 100.f, -520.f);
  185.   glVertex3f(100.f, -100.f, -520.f);
  186.  
  187.   /* ceiling */
  188.   glNormal3f(0.f, -1.f, 0.f);
  189.   glVertex3f(-100.f, 100.f, -320.f);
  190.   glVertex3f(-100.f, 100.f, -520.f);
  191.   glVertex3f(100.f, 100.f, -520.f);
  192.   glVertex3f(100.f, 100.f, -320.f);
  193.  
  194.   /* back wall */
  195.   glNormal3f(0.f, 0.f, 1.f);
  196.   glVertex3f(-100.f, -100.f, -520.f);
  197.   glVertex3f(100.f, -100.f, -520.f);
  198.   glVertex3f(100.f, 100.f, -520.f);
  199.   glVertex3f(-100.f, 100.f, -520.f);
  200.   glEnd();
  201.  
  202.   cone();
  203.  
  204.   sphere();
  205.  
  206.   glCallList(LIGHT);
  207.  
  208.   /* draw shadowing object */
  209.   glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, shad_mat);
  210.   glBegin(GL_POLYGON);
  211.   glNormal3fv(obj->normal);
  212.   for (v = obj->verticies, i = 0; i < obj->n; i++) {
  213.     glVertex3fv(v);
  214.     v += 3;
  215.   }
  216.   glEnd();
  217.  
  218. }
  219.  
  220. void
  221. redraw(void)
  222. {
  223.   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
  224.   switch (rendermode) {
  225.   case NONE:
  226.     render(&shadower);
  227.     break;
  228.   case NOLIGHT:
  229.     glDisable(GL_LIGHT0);
  230.     render(&shadower);
  231.     glEnable(GL_LIGHT0);
  232.     break;
  233.   case VOLUME:
  234.     render(&shadower);
  235.     glCallList(SHADOWVOL);
  236.     break;
  237.   case SHADOW:
  238.     glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
  239.     render(&shadower);  /* render scene in depth buffer */
  240.  
  241.     glEnable(GL_STENCIL_TEST);
  242.     glDepthMask(GL_FALSE);
  243.     glStencilFunc(GL_ALWAYS, 0, 0);
  244.  
  245.     glStencilOp(GL_KEEP, GL_KEEP, GL_INCR);
  246.     glCullFace(GL_BACK);  /* increment using front face of shadow volume */
  247.     glCallList(SHADOWVOL);
  248.  
  249.     glStencilOp(GL_KEEP, GL_KEEP, GL_DECR);
  250.     glCullFace(GL_FRONT);  /* increment using front face of shadow volume */
  251.     glCallList(SHADOWVOL);
  252.  
  253.     glDepthMask(GL_TRUE);
  254.     glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
  255.     glCullFace(GL_BACK);
  256.     glDepthFunc(GL_LEQUAL);
  257.     glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
  258.  
  259.     glStencilFunc(GL_EQUAL, 1, 1);  /* draw shadowed part */
  260.     glDisable(GL_LIGHT0);
  261.     render(&shadower);
  262.  
  263.     glStencilFunc(GL_EQUAL, 0, 1);  /* draw lit part */
  264.     glEnable(GL_LIGHT0);
  265.     render(&shadower);
  266.  
  267.     glDepthFunc(GL_LESS);
  268.     glDisable(GL_STENCIL_TEST);
  269.     break;
  270.   }
  271.  
  272.   glutSwapBuffers();    /* high end machines may need this */
  273. }
  274.  
  275. /* ARGSUSED1 */
  276. void 
  277. key(unsigned char key, int x, int y)
  278. {
  279.   if (key == '\033')
  280.     exit(0);
  281. }
  282.  
  283. const int TEXDIM = 256;
  284. /* Parse arguments, and set up interface between OpenGL and window system */
  285. int
  286. main(int argc, char *argv[])
  287. {
  288.   GLfloat *tex;
  289.   GLUquadricObj *sphere, *cone, *base;
  290.   static GLfloat sphere_mat[] =
  291.   {1.f, .5f, 0.f, 1.f};
  292.   static GLfloat cone_mat[] =
  293.   {0.f, .5f, 1.f, 1.f};
  294.  
  295.   glutInit(&argc, argv);
  296.   glutInitWindowSize(512, 512);
  297.   glutInitDisplayMode(GLUT_RGBA | GLUT_DEPTH | GLUT_STENCIL | GLUT_DOUBLE);
  298.   (void) glutCreateWindow("shadow volumes");
  299.   glutDisplayFunc(redraw);
  300.   glutKeyboardFunc(key);
  301.  
  302.   glutCreateMenu(menu);
  303.   glutAddMenuEntry("No Shadows", NONE);
  304.   glutAddMenuEntry("No Light", NOLIGHT);
  305.   glutAddMenuEntry("Show Volume", VOLUME);
  306.   glutAddMenuEntry("Shadows", SHADOW);
  307.   glutAttachMenu(GLUT_RIGHT_BUTTON);
  308.  
  309.   /* draw a perspective scene */
  310.   glMatrixMode(GL_PROJECTION);
  311.   glFrustum(-100., 100., -100., 100., 320., 640.);
  312.   glMatrixMode(GL_MODELVIEW);
  313.  
  314.   /* turn on features */
  315.   glEnable(GL_DEPTH_TEST);
  316.   glEnable(GL_LIGHTING);
  317.   glEnable(GL_LIGHT0);
  318.   glEnable(GL_CULL_FACE);
  319.  
  320.   /* place light 0 in the right place */
  321.   glLightfv(GL_LIGHT0, GL_POSITION, lightpos);
  322.  
  323.   /* remove back faces to speed things up */
  324.   glCullFace(GL_BACK);
  325.  
  326.   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  327.  
  328.   /* make display lists for sphere and cone; for efficiency */
  329.  
  330.   glNewList(SPHERE, GL_COMPILE);
  331.   sphere = gluNewQuadric();
  332.   glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, sphere_mat);
  333.   gluSphere(sphere, 20.f, 20, 20);
  334.   gluDeleteQuadric(sphere);
  335.   glEndList();
  336.  
  337.   glNewList(CONE, GL_COMPILE);
  338.   cone = gluNewQuadric();
  339.   base = gluNewQuadric();
  340.   glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, cone_mat);
  341.   glRotatef(-90.f, 1.f, 0.f, 0.f);
  342.   gluDisk(base, 0., 20., 20, 1);
  343.   gluCylinder(cone, 20., 0., 60., 20, 20);
  344.   gluDeleteQuadric(cone);
  345.   gluDeleteQuadric(base);
  346.   glEndList();
  347.  
  348.   glNewList(LIGHT, GL_COMPILE);
  349.   sphere = gluNewQuadric();
  350.   glPushMatrix();
  351.   glTranslatef(lightpos[X], lightpos[Y], lightpos[Z]);
  352.   glDisable(GL_LIGHTING);
  353.   glColor3f(.9f, .9f, .6f);
  354.   gluSphere(sphere, 5.f, 20, 20);
  355.   glEnable(GL_LIGHTING);
  356.   glPopMatrix();
  357.   gluDeleteQuadric(sphere);
  358.   glEndList();
  359.  
  360.   /* load pattern for current 2d texture */
  361.   tex = make_texture(TEXDIM, TEXDIM);
  362.   glTexImage2D(GL_TEXTURE_2D, 0, 1, TEXDIM, TEXDIM, 0, GL_RED, GL_FLOAT, tex);
  363.   free(tex);
  364.  
  365.   shadower.verticies = shadVerts;
  366.   shadower.normal = shadNormal;
  367.   shadower.n = sizeof(shadVerts) / (3 * sizeof(GLfloat));
  368.  
  369.   makeShadowVolume(&shadower, lightpos, 10.f, SHADOWVOL);
  370.  
  371.   glutMainLoop();
  372.   return 0;             /* ANSI C requires main to return int. */
  373. }
  374.